#ifndef _sdl_app_h_
#define _sdl_app_h_

#include <string>
#include <cstdlib>
#include <fstream>
#include "sdl_debug.h"
#include "sdl_prim.h"
#include "sdl_layer.h"
#include "sdl_engine.h"
#include "sdl_resource.h"
#include "boost/program_options.hpp"
#include "boost/filesystem.hpp"
#include "boost/algorithm/string.hpp"
#include "sdl_options.h"

#ifndef sdl_config_file
#define sdl_config_file "nkfsdl.ini"
#endif

class sdl_app : public sdl_layer {
    //
    // ku przestrodze - ponieważ to jest sdl_layer, engine zawiera pointer do sdl_app. W ten sposób ten obiekt nigdy nie zostanie uwolniony.
    // Być może kiedyś to stanie się mniej istotne (w końcu sam sdl_engine i sdl_app to tylko kilka kB)
    // sdl_ptr<sdl_engine>			engine;
public:

    sdl_app(int argc, char ** argv) :
    sdl_layer(10, std::string(argv[0])) {
        sdl_ptr<sdl_options> options = give<sdl_options > ();
        sdl_ptr<sdl_debug::debug> debug = give<sdl_debug::debug > ();
        po::options_description desc;
        desc.add_options()
                ("help,h", "produce help message")
                ("debug.enable,d", "produce debug output")
                ("debug.disable,n", "suppress debug output")
                ("debug.lowlevel", po::value<int>(&sdl_prim::__debug_level), "set the debug level for internal memory management messages, values that generate output are 2,3")
                ("debug.level", po::value<int>(), "set global debug level")
                ("debug.method", po::value<std::string > (), "can be cout or file, otherwise treated as file name")
                ("debug.channel.levels", po::value<std::vector<std::string> >()->composing(), "set debug level of a channel")
                ("debug.channel.methods", po::value<std::vector<std::string> >()->multitoken()->composing(), "set output methods for specified channels, can be cout or file, otherwise treated as file name")
                ("media.directories,M", po::value<std::vector<std::string> >()->multitoken()->composing(), "set media search directories")
                ;
        namespace bf = boost::filesystem;

        options->read_command_line(argc, argv, desc);
        // te opcje i tak mają zły format, w zmiennych środowiskowych nie może być - ani .
        //options->read_environment(desc);
        if (bf::exists(sdl_config_file)) {
            std::ifstream cfg(sdl_config_file);
            options->read_config_file(cfg, desc);
            cfg.close();
        }
        if (options->is_set("help")) {
            debug->disable_messages();
            std::cout << desc << std::endl;
        }
        if (options->is_set("debug.enable")) {
            debug->enable_messages();
        }
        if (options->is_set("debug.disable")) {
            debug->disable_messages();
        }
        if (options->is_set("debug.level")) {
            debug->set_lowpass(options->get<int>("debug.level"));
        }
        if (options->is_set("debug.channel.levels")) {
            std::vector<std::string> vals = options->get<std::vector<std::string> >("debug.channel.levels");
            for (int i = 0; i < vals.size(); i++) {
                std::vector<std::string> tuple;
                boost::split(tuple, vals[i], boost::is_any_of("=,;:"));
                if (tuple.size() > 1)
                    debug->set_lowpass(tuple[0], std::atoi(tuple[1].c_str()));
            }
        }
        if (options->is_set("debug.method")) {
            std::string val = options->get<std::string > ("debug.method");
            if (val == std::string("cout"))
                debug->set_output_method(sdl_debug::ostdout);
            else if (val == std::string("file"))
                debug->set_output_method(sdl_debug::ofile);
            else {
                debug->set_custom_output((std::ostream*)(new std::ofstream(val.c_str())));
            }
        }
        if (options->is_set("debug.channel.methods")) {
            std::vector<std::string> vals = options->get<std::vector<std::string> >("debug.channel.methods");
            for (int i = 0; i < vals.size(); i++) {
                std::vector<std::string> tuple;
                boost::split(tuple, vals[i], boost::is_any_of("=,;:"));
                if (tuple.size() > 1) {
                    if (tuple[1] == std::string("cout"))
                        debug->set_output_method(tuple[0], sdl_debug::ostdout);
                    else if (tuple[1] == std::string("file"))
                        debug->set_output_method(tuple[0], sdl_debug::ofile);
                    else {
                        debug->set_custom_output(tuple[0], (std::ostream*)(new std::ofstream(tuple[1].c_str())));
                    }
                }
            }
        }
    }

    virtual void run() {
        give<sdl_engine > ()->run();
    }
};




#endif //_sdl_app_h_
